﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Base.DAL;
using Base.Util;
using System.IO.Ports;
using System.Text.RegularExpressions;
using System.Collections.Concurrent;
using System.Timers;

namespace Base.BLL
{
    /// <summary>
    /// 串口数据服务
    /// 从串口接收数据并解析存入数据库
    /// </summary>
    public class ComService
    {
        public static ComService cs = new ComService();

        #region 属性

        /// <summary>
        /// 计时器列表，每个测区对应一个计时器，用于执行数据存储、计算等操作
        /// </summary>
        //private Dictionary<int, Timer> timers=new Dictionary<int,Timer>();

        

        Timer timer = null;

        public int StorageSpan = 30;
        private string lastError;
        /// <summary>
        /// 最近一次错误信息
        /// </summary>
        public string LastError { get { string _lastError = lastError; lastError = ""; return _lastError; } }

        /// <summary>
        /// 数据缓冲池
        /// </summary>
        private ConcurrentDictionary<DATA_TYPE, ConcurrentQueue<IEntity>> dataPool = new ConcurrentDictionary<DATA_TYPE, ConcurrentQueue<IEntity>>();        
        /// <summary>
        /// 串口列表，与测区编号一一对应
        /// </summary>
        private Dictionary<int, ComHelper> coms = new Dictionary<int, ComHelper>();
        /// <summary>
        /// 串口号-测区号映射
        /// </summary>
        private Dictionary<string, int> com2cq = new Dictionary<string, int>();
        /// <summary>
        /// 是否已启动
        /// </summary>
        private bool _isStart=false;
        public bool IsStart { get { return _isStart; } }
        #endregion
        /// <summary>
        /// 构造方法，从配置中加载所有串口并初始化
        /// </summary>
        public ComService()
        {
            DataParseService.Load();
            StorageSpan = int.Parse(ConfigService.GetIni("StorageSpan","30"));
            if(StorageSpan>60)
            {
                StorageSpan = 60;
            }
            string sql=@"SELECT CQBH,SYSTEMCOMB.COM,BTL,JYW,SJW,TZW 
                         FROM SYSTEMCQB INNER JOIN SYSTEMCOMB ON SYSTEMCQB.COM=SYSTEMCOMB.COM
                         WHERE ZT=1";
            foreach (var cq in Db.Query<ComIni>(sql))
            {
                com2cq.Add(cq.COM, cq.CQBH);
                Parity parity;
                switch(cq.JYW.ToUpper())
                {                    
                    case "NONE":parity=Parity.None;break;
                    case "EVEN":parity=Parity.Even;break;
                    case "MARK":parity=Parity.Mark;break;
                    case "ODD":parity=Parity.Odd;break;
                    case "SPACE":parity=Parity.Space;break;
                    default:parity=Parity.None;break;
                }
                StopBits stopBits;
                switch(cq.TZW.ToUpper())
                {                    
                    case "1":stopBits=StopBits.One;break;
                    case "2":stopBits=StopBits.Two;break;
                    case "1.5":stopBits=StopBits.OnePointFive;break;
                    case "NONE":stopBits=StopBits.None;break;                    
                    default:stopBits=StopBits.One;break;
                }
                ComHelper com=new ComHelper(cq.COM, int.Parse(cq.BTL), parity, int.Parse(cq.SJW), stopBits);
                com.DataReceived += new ComHelper.SerialPortDataReceiveEventArgs(DataRec);
                coms.Add(cq.CQBH, com);
            }
        }

        /// <summary>
        /// 析构方法，关闭串口，停止数据处理线程
        /// </summary>
        ~ComService()
        {
            Stop();            
        }
        /// <summary>
        /// 数据存储操作
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private void Storage(object source, ElapsedEventArgs e)
        {
            Console.WriteLine("保存数据...");
            foreach (var d in dataPool)
            {
                //存储数据
                DataParseService.Parsers[d.Key].Storage(d.Value);
            }
            DataParseService.Calc();
        }
        /// <summary>
        /// 串口数据到达
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <param name="bits"></param>
        public void DataRec(object sender, SerialDataReceivedEventArgs e, byte[] bits)
        {
            int cqbh = com2cq[((SerialPort)sender).PortName];
            DataParseService parser = new DataParseService(cqbh, bits);
            parser.DataParsed += new DataParseService.OnDataParsed(DataParsed);
            //if (!parser.IsCorrect())
            //{
            //    return;
            //}
            parser.Parse();
        }
        /// <summary>
        /// 成功解析出串口数据，将其加入数据缓冲池中
        /// </summary>
        /// <param name="type">串口数据类型</param>
        /// <param name="data">解析后的数据</param>
        public void DataParsed(DATA_TYPE type, object data)
        {
            Console.WriteLine("成功解析数据");
            if (!dataPool.ContainsKey(type))
            {
                dataPool.TryAdd(type, new ConcurrentQueue<IEntity>());
            }
            ConcurrentQueue<IEntity> lst = dataPool[type];
            lst.Enqueue((IEntity)data);
        }
        /// <summary>
        /// 判断串口是否打开
        /// </summary>
        /// <param name="cqbh">测区编号</param>
        /// <returns>串口是否已被打开</returns>
        public bool IsOpen(int cqbh)
        {
            return coms.ContainsKey(cqbh) && coms[cqbh].IsOpen;
        }
        /// <summary>
        /// 打开监听端口
        /// </summary>
        /// <param name="cqbh">测区编号</param>
        /// <returns></returns>
        public bool OpenPort(int cqbh)
        {
            try
            {
                if (coms.ContainsKey(cqbh))
                {
                    coms[cqbh].openPort();
                }
                return true;
            }
            catch (Exception ex)
            {
                LoggerHelper.Error(ex);
                lastError = ex.Message;
            }
            return false;
        }
        /// <summary>
        /// 打开所有串口
        /// </summary>
        /// <returns></returns>
        public void OpenPort()
        {
            foreach (var q in coms)
            {
                try
                {
                    q.Value.openPort();
                }
                catch (Exception ex)
                {
                    LoggerHelper.Error(ex);
                    lastError = ex.Message;
                }
            }
        }
        /// <summary>
        /// 关闭测区串口
        /// </summary>
        /// <param name="cqbh"></param>
        /// <returns></returns>
        public bool ClosePort(int cqbh)
        {
            try
            {
                if (coms.ContainsKey(cqbh))
                {
                    coms[cqbh].closePort();
                }
                return true;
            }
            catch (Exception ex)
            {
                LoggerHelper.Error(ex);
                lastError = ex.Message;
            }
            return false;
        }
        /// <summary>
        /// 关闭所有串口
        /// </summary>
        public void ClosePort()
        {
            foreach (var q in coms)
            {
                try
                {
                    q.Value.closePort();
                }
                catch (Exception ex)
                {
                    LoggerHelper.Error(ex);
                    lastError = ex.Message;
                }
            }
        }

        public void Start()
        {
            if (_isStart)
                return;
            OpenPort();
            timer = new Timer();
            timer.Interval = StorageSpan*1000;//每30秒记录一次数据
            timer.Elapsed += new ElapsedEventHandler(Storage);
            timer.Start();
            _isStart = true;
        }
        public void Stop()
        {
            try
            {
                //关闭所有串口
                ClosePort();
                //停止存储操作
                if (timer != null)
                {
                    timer.Stop();
                    timer = null;
                    //保存缓冲区内数据
                    Storage(this, null);
                    //计算加权平均值
                    DataParseService.CalcAnyway();
                }
                _isStart = false;
            }
            catch (Exception e)
            {
                LoggerHelper.Error(e);
            }
        }
        public static void Test()
        {
            ComService comService = new ComService();
            //comService.OpenPort(1);
            comService.Start();
        }
    }
    class ComIni
    {
        public int CQBH;//测区编号
        public string COM;//串口号
        public string BTL;//波特率
        public string JYW;//校验位
        public string SJW;//数据位
        public string TZW;//停止位
    }
    
}
